package org.acghub.mtdb.core;

import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.acghub.mtdb.common.*;
import org.acghub.mtdb.common.exception.LifecycleException;
import org.acghub.mtdb.common.exception.MtdbException;

import java.util.Collection;
import java.util.concurrent.ScheduledExecutorService;

/**
 * @author zhouhe
 */
@Slf4j
@SuppressWarnings("all")
public final class Mtdb implements Lifecycle<Pair<org.acghub.mtdb.common.Mtdb, Config>> {

    public static final Mtdb INSTANCE = new Mtdb();
    private org.acghub.mtdb.common.Mtdb meta;
    private Config config;
    private Tables tables;
    private StorageEngine storageEngine;

    private Mtdb() {
    }

    @Override
    public void init(Pair<org.acghub.mtdb.common.Mtdb, Config> mtdbConfigPair) throws LifecycleException {
        meta = mtdbConfigPair.getKey();
        config = mtdbConfigPair.getValue();

        // 1.锁初始化
        try {
            Lockeys.INSTANCE.init(config);
        } catch (Exception e) {
            log.error("lockeys init error", e);
            if (e instanceof LifecycleException) {
                throw (LifecycleException) e;
            }
            throw new LifecycleException(e);
        }


        // 2.存储引擎初始化
        try {
            Config.StorageEngineConfig storageEngineConfig = config.getStorageEngineConfig();
            storageEngine = storageEngineConfig.getStorageEngineType().newInstance();
            storageEngine.init(config);
        } catch (Exception e) {
            log.error("storage engine init error", e);
            if (e instanceof LifecycleException) {
                throw (LifecycleException) e;
            }
            throw new LifecycleException(e);
        }

        // 3.所有表初始化
        try {
            String tableClass = config.tableFullPackage() + "._Tables_";
            Class<?> clazz = Class.forName(tableClass);
            tables = (Tables) clazz.getField("INSTANCE").get(null);
            Pair<org.acghub.mtdb.common.Mtdb, StorageEngine> pair = Pair.of(meta, storageEngine);
            tables.init(pair);
        } catch (Exception e) {
            log.error("init tables error", e);
            if (e instanceof LifecycleException) {
                throw (LifecycleException) e;
            }
            throw new LifecycleException(e);
        }

        // 4.procedure executors 初始化
        Procedures.INSTANCE.init(config);
    }

    @Override
    public void close() throws LifecycleException {
        //1. 先关闭用户逻辑
        Procedures.INSTANCE.close();
        tables.close();
        storageEngine.close();
        Lockeys.INSTANCE.close();
    }

    public org.acghub.mtdb.common.Mtdb meta() {
        return meta;
    }

    public Config config() {
        return config;
    }


    public void start() throws Exception {
        log.info("mtdb start begin");
        // 1.配置初始化
        String jsonStr = ResourceUtil.readUtf8Str("mtdb.json");
        Config config = JSONUtil.toBean(jsonStr, Config.class);
        config.init();

        // 构造mtdb meta
        org.acghub.mtdb.common.Mtdb mtdb = TypeFactory.create(org.acghub.mtdb.common.Mtdb.class, Root.DEFAULT_ROOT, config.getElement());

        // 2.编译
        this.compile(mtdb);

        // 3.
        this.init(Pair.of(mtdb, config));

        log.info("mtdb start success");
    }

    private void compile(org.acghub.mtdb.common.Mtdb mtdb) throws Exception {
        // 2.初始化类型工厂
        TypeFactory.init();
        Collection<Compilable> list = mtdb.compile();
        if (!list.isEmpty()) {
            System.err.println("================================ 编译❌😔 ================================");
            for (Compilable compile : list) {
                System.err.println("\t" + compile);
            }
            throw new MtdbException("compile error");
        }
        System.out.println("================================ 编译✅😊 ================================");
    }

    public void stop() throws Exception {
        log.info("mtdb stop begin");
        this.close();
        log.info("mtdb stop success");
    }

    public ScheduledExecutorService scheduler() {
        return null;
    }
}
